/*
 *  Copyright (C) 2010 Glauco
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.annotation.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.balisunrise.annotation.VisualEntity;
import org.balisunrise.annotation.Grid;

/**
 * Esta classe contém os atributos para construção de um grid de uma entidade.
 *
 * @author Glauco
 */
public class GridUtilities extends VisualEntityUtilities{

    private static final String MESSAGE = "Erro ao ler Annotation \"Grid\".";

    /**
     * Largura do grid.<br>
     * Utilize o valor zero (0) para a largura do grid ser a mesma da largura
     * das colunas.
     */
    public int width;

    /**
     * Altura do grid.
     */
    public int height;

    /**
     * Alias da ordem.
     */
    public String order;

    /**
     * Quantidade de colunas (atributos) do grid.
     */
    public int length;

    /**
     * Listas das Colunas do Grid.
     */
    public List<ColumnUtilities> columns;

    /**
     * Lista de ordenação do grid.
     */
    public List<OrderUtilities> orders;

    /**
     * Cria um GridUtilities
     */
    public GridUtilities(){
        columns = new ArrayList<ColumnUtilities>();
        orders = new ArrayList<OrderUtilities>();
    }

    /**
     * Le a Anotação grid de uma classe.
     * @param entityClass A Class a ser lida.
     * @param alias O Alias de deve ser buscado.
     * @return A Anotação Grid correspondente.
     * @throws AnnotationsUtilitiesException caso não encontre nenhuma anotação
     * grid para o alias ou a Class for nula é retornado a exceção.
     */
    public static Grid readGridAnnotation(Class entityClass,String alias)
            throws AnnotationsUtilitiesException {

        if(entityClass == null)
            throw new AnnotationsUtilitiesException(MESSAGE +
                    "\nParâmentro \"entityClass\" não pode ser nulo!");

        if (alias == null)
            throw new AnnotationsUtilitiesException(MESSAGE +
                    "\nParâmentro \"alias\" não pode ser nulo!");


        VisualEntity ve = readVisualEntityAnnotation(entityClass);
        for (int i = 0; i < ve.grids().length; i++) {
            Grid grid =  ve.grids()[i];
            for (int j = 0; j < grid.alias().length; j++) {
                if(grid.alias()[j].equals(alias))
                    return grid;
            }
        }

        throw new AnnotationsUtilitiesException(MESSAGE +
                    "\nAnnotation \"Grid\" não encontrada para o " +
                    "nome\""+ alias +"\"!");
    }

    /**
     * Le a annotation Grid e cria um GridUtilities a parir dos dados da
     * annotation.
     *
     * @param entityClass Classe para ler.
     * @param alias alias da Grid.
     * @return GridUtilities
     * @throws AnnotationsUtilitiesException Caso não encontre a annotation ou
     * algum parâmetro seja nulo.
     */
    public static GridUtilities create(Class entityClass,String alias)
            throws AnnotationsUtilitiesException {

        if (entityClass == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"entityClass\" não pode ser nulo!");

        if (alias == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"alias\" não pode ser nulo!");

        // le anotação Grid
        Grid g = readGridAnnotation(entityClass, alias);

        GridUtilities gu = new GridUtilities();
        gu.entityClass = entityClass;
        gu.alias = alias;
        gu.title = g.title();
        gu.height = g.height();
        gu.width = g.width();
        gu.order = g.order();

        // para cada campo da classe, cria os filtros.
        ReflectUtilities ru = new ReflectUtilities(entityClass);
        for (Field field : ru.getDeclaredFields()) {
            try{
                gu.columns.add(ColumnUtilities.create(field, alias));
            }catch(AnnotationsUtilitiesException aue){
                // Não importa se ocorreu exceção,
                // apenas não inclui o campo na lista.
            }
            try{
                gu.orders.add(OrderUtilities.create(field, gu.order));
            }catch(AnnotationsUtilitiesException aue){
                // Não importa se ocorreu exceção,
                // apenas não inclui o campo na lista.
            }
        }

        // ordena as colunas
        ColumnUtilities.sort(gu.columns);

        // ordena as ordens
        OrderUtilities.sort(gu.orders);

        // verifica os filtros embedded e selection
        for (ColumnUtilities gcu : gu.columns) {
            if (gcu.type != ColumnUtilities.DEFINITION){
                GridUtilities guAux = create(gcu.field.getType(), gcu.call);
                gcu.embedded = guAux.columns;
            }
        }

        // conta número de colunas
        gu.length = 0;
        for (ColumnUtilities gcu : gu.columns) {
            gu.length += gcu.count();
        }
        
        return gu;
    }
}
